<template>
  <div class="videoBgRemove">
    <video id="video"
           src="/8_1736396574.mp4"
           loop
           autoplay
           muted
           ref="video"
           style="width: 240px;"></video>
    <canvas id="output-canvas"
            width="200"
            height="450"
            willReadFrequently="true"
            ref="canvas"></canvas>
  </div>
</template>

<script>
export default {
  data () {
    return {
      video: null,
      canvas: null,
      ctx: null,
      canvas_tmp: null,
      ctx_tmp: null,
      featherStrength: 0.4, // 羽化强度控制
    };
  },
  methods: {
    init () {
      this.ctx = this.canvas.getContext('2d');
      this.canvas_tmp = document.createElement('canvas');
      this.canvas_tmp.setAttribute('width', 200);
      this.canvas_tmp.setAttribute('height', 450);
      this.ctx_tmp = this.canvas_tmp.getContext('2d');
      this.video.addEventListener('play', this.computeFrame);
    },

    numToPoint (num, width) {
      let col = num % width;
      let row = Math.floor(num / width);
      row = col === 0 ? row : row + 1;
      col = col === 0 ? width : col;
      return [row, col];
    },

    pointToNum (point, width) {
      let [row, col] = point;
      return (row - 1) * width + col;
    },

    getAroundPoint (point, width, height, area) {
      let [row, col] = point;
      let allAround = [];
      if (row > height || col > width || row < 0 || col < 0) return allAround;
      for (let i = 0; i < area; i++) {
        let pRow = row - 1 + i;
        for (let j = 0; j < area; j++) {
          let pCol = col - 1 + j;
          if (i === area % 2 && j === area % 2) continue;
          allAround.push([pRow, pCol]);
        }
      }
      return allAround.filter(([iRow, iCol]) => {
        return iRow > 0 && iCol > 0 && iRow <= height && iCol <= width;
      });
    },

    computeFrame () {
      if (this.video) {
        if (this.video.paused || this.video.ended) return;
      }
      this.ctx_tmp.drawImage(this.video, 0, 0, this.video.clientWidth, this.video.clientHeight);

      let frame = this.ctx_tmp.getImageData(0, 0, this.video.clientWidth, this.video.clientHeight);

      const height = frame.height;
      const width = frame.width;
      const pointLens = frame.data.length / 4;

      // 背景透明化（假设背景为特定颜色，这里选择绿色）
      for (let i = 0; i < pointLens; i++) {
        let r = frame.data[i * 4];
        let g = frame.data[i * 4 + 1];
        let b = frame.data[i * 4 + 2];
        if (r < 100 && g > 120 && b < 200) {
          frame.data[i * 4 + 3] = 0;
        }
      }

      const tempData = [...frame.data];
      for (let i = 0; i < pointLens; i++) {
        if (frame.data[i * 4 + 3] === 0) continue;
        const currentPoint = this.numToPoint(i + 1, width);
        const arroundPoint = this.getAroundPoint(currentPoint, width, height, 3);

        let opNum = 0;
        let rSum = 0;
        let gSum = 0;
        let bSum = 0;
        arroundPoint.forEach((position) => {
          const index = this.pointToNum(position, width);
          rSum += tempData[(index - 1) * 4];
          gSum += tempData[(index - 1) * 4 + 1];
          bSum += tempData[(index - 1) * 4 + 2];
          if (tempData[(index - 1) * 4 + 3] !== 255) opNum++;
        });

        let alpha = (255 / arroundPoint.length) * (arroundPoint.length - opNum);

        // 调整羽化效果
        if (alpha !== 255) {
          frame.data[i * 4] = parseInt(rSum / arroundPoint.length);
          frame.data[i * 4 + 1] = parseInt(gSum / arroundPoint.length);
          frame.data[i * 4 + 2] = parseInt(bSum / arroundPoint.length);

          // 根据羽化强度调整 alpha
          frame.data[i * 4 + 3] = parseInt(alpha * this.featherStrength);
        }
      }

      this.ctx.putImageData(frame, 0, 0);
      setTimeout(this.computeFrame, 0);
    }
  },

  mounted () {
    this.video = this.$refs.video;
    this.canvas = this.$refs.canvas;
    this.init();
  }
};
</script>

